/*
 * $RCSfile: GVector.java,v $
 *
 * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 *
 * $Revision: 1.7 $
 * $Date: 2008/02/28 20:18:50 $
 * $State: Exp $
 */

package etrl.vecmath;

/**
 * A double precision, general, dynamically-resizable, one-dimensional vector
 * class. Index numbering begins with zero.
 */
public class GVector implements java.io.Serializable, Cloneable {

	private int length;
	double[] values;

	// Compatible with 1.1
	static final long serialVersionUID = 1398850036893875112L;

	/**
	 * Constructs a new GVector of the specified length with all vector elements
	 * initialized to 0.
	 * 
	 * @param length
	 *          the number of elements in this GVector.
	 */
	public GVector(int length) {
		int i;

		this.length = length;
		values = new double[length];
		for (i = 0; i < length; i++)
			values[i] = 0.0;
	}

	/**
	 * Constructs a new GVector from the specified array elements. The length of
	 * this GVector is set to the length of the specified array. The array
	 * elements are copied into this new GVector.
	 * 
	 * @param vector
	 *          the values for the new GVector.
	 */
	public GVector(double[] vector) {
		int i;

		length = vector.length;
		values = new double[vector.length];
		for (i = 0; i < length; i++)
			values[i] = vector[i];
	}

	/**
	 * Constructs a new GVector from the specified vector. The vector elements are
	 * copied into this new GVector.
	 * 
	 * @param vector
	 *          the source GVector for this new GVector.
	 */
	public GVector(GVector vector) {
		int i;

		values = new double[vector.length];
		length = vector.length;
		for (i = 0; i < length; i++)
			values[i] = vector.values[i];
	}

	/**
	 * Constructs a new GVector and copies the initial values from the specified
	 * tuple.
	 * 
	 * @param tuple
	 *          the source for the new GVector's initial values
	 */
	public GVector(Tuple2f tuple) {
		values = new double[2];
		values[0] = (double) tuple.x;
		values[1] = (double) tuple.y;
		length = 2;
	}

	/**
	 * Constructs a new GVector and copies the initial values from the specified
	 * tuple.
	 * 
	 * @param tuple
	 *          the source for the new GVector's initial values
	 */
	public GVector(Tuple3f tuple) {
		values = new double[3];
		values[0] = (double) tuple.x;
		values[1] = (double) tuple.y;
		values[2] = (double) tuple.z;
		length = 3;
	}

	/**
	 * Constructs a new GVector and copies the initial values from the specified
	 * tuple.
	 * 
	 * @param tuple
	 *          the source for the new GVector's initial values
	 */
	public GVector(Tuple3d tuple) {
		values = new double[3];
		values[0] = tuple.x;
		values[1] = tuple.y;
		values[2] = tuple.z;
		length = 3;
	}

	/**
	 * Constructs a new GVector and copies the initial values from the specified
	 * tuple.
	 * 
	 * @param tuple
	 *          the source for the new GVector's initial values
	 */
	public GVector(Tuple4f tuple) {
		values = new double[4];
		values[0] = (double) tuple.x;
		values[1] = (double) tuple.y;
		values[2] = (double) tuple.z;
		values[3] = (double) tuple.w;
		length = 4;
	}

	/**
	 * Constructs a new GVector and copies the initial values from the specified
	 * tuple.
	 * 
	 * @param tuple
	 *          the source for the new GVector's initial values
	 */
	public GVector(Tuple4d tuple) {
		values = new double[4];
		values[0] = tuple.x;
		values[1] = tuple.y;
		values[2] = tuple.z;
		values[3] = tuple.w;
		length = 4;
	}

	/**
	 * Constructs a new GVector of the specified length and initializes it by
	 * copying the specified number of elements from the specified array. The
	 * array must contain at least <code>length</code> elements (i.e.,
	 * <code>vector.length</code> >= <code>length</code>. The length of this new
	 * GVector is set to the specified length.
	 * 
	 * @param vector
	 *          The array from which the values will be copied.
	 * @param length
	 *          The number of values copied from the array.
	 */
	public GVector(double vector[], int length) {
		int i;

		this.length = length;
		values = new double[length];
		for (i = 0; i < length; i++) {
			values[i] = vector[i];
		}
	}

	/**
	 * Returns the square root of the sum of the squares of this vector (its
	 * length in n-dimensional space).
	 * 
	 * @return length of this vector
	 */

	public final double norm() {
		double sq = 0.0;
		int i;

		for (i = 0; i < length; i++) {
			sq += values[i] * values[i];
		}

		return (Math.sqrt(sq));

	}

	/**
	 * Returns the sum of the squares of this vector (its length squared in
	 * n-dimensional space).
	 * 
	 * @return length squared of this vector
	 */
	public final double normSquared() {
		double sq = 0.0;
		int i;

		for (i = 0; i < length; i++) {
			sq += values[i] * values[i];
		}

		return (sq);
	}

	/**
	 * Sets the value of this vector to the normalization of vector v1.
	 * 
	 * @param v1
	 *          the un-normalized vector
	 */
	public final void normalize(GVector v1) {
		double sq = 0.0;
		int i;

		if (length != v1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector0"));

		for (i = 0; i < length; i++) {
			sq += v1.values[i] * v1.values[i];
		}

		double invMag;
		invMag = 1.0 / Math.sqrt(sq);

		for (i = 0; i < length; i++) {
			values[i] = v1.values[i] * invMag;
		}
	}

	/**
	 * Normalizes this vector in place.
	 */
	public final void normalize() {
		double sq = 0.0;
		int i;

		for (i = 0; i < length; i++) {
			sq += values[i] * values[i];
		}

		double invMag;
		invMag = 1.0 / Math.sqrt(sq);

		for (i = 0; i < length; i++) {
			values[i] = values[i] * invMag;
		}

	}

	/**
	 * Sets the value of this vector to the scalar multiplication of the scale
	 * factor with the vector v1.
	 * 
	 * @param s
	 *          the scalar value
	 * @param v1
	 *          the source vector
	 */
	public final void scale(double s, GVector v1) {
		int i;
		if (length != v1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector1"));

		for (i = 0; i < length; i++) {
			values[i] = v1.values[i] * s;
		}
	}

	/**
	 * Scales this vector by the scale factor s.
	 * 
	 * @param s
	 *          the scalar value
	 */
	public final void scale(double s) {
		int i;

		for (i = 0; i < length; i++) {
			values[i] = values[i] * s;
		}
	}

	/**
	 * Sets the value of this vector to the scalar multiplication by s of vector
	 * v1 plus vector v2 (this = s*v1 + v2).
	 * 
	 * @param s
	 *          the scalar value
	 * @param v1
	 *          the vector to be multiplied
	 * @param v2
	 *          the vector to be added
	 */
	public final void scaleAdd(double s, GVector v1, GVector v2) {

		int i;

		if (v2.length != v1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector2"));

		if (length != v1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector3"));

		for (i = 0; i < length; i++) {
			values[i] = v1.values[i] * s + v2.values[i];
		}
	}

	/**
	 * Sets the value of this vector to sum of itself and the specified vector
	 * 
	 * @param vector
	 *          the second vector
	 */
	public final void add(GVector vector) {
		int i;

		if (length != vector.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector4"));

		for (i = 0; i < length; i++) {
			this.values[i] += vector.values[i];
		}
	}

	/**
	 * Sets the value of this vector to the vector sum of vectors vector1 and
	 * vector2.
	 * 
	 * @param vector1
	 *          the first vector
	 * @param vector2
	 *          the second vector
	 */
	public final void add(GVector vector1, GVector vector2) {
		int i;

		if (vector1.length != vector2.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector5"));

		if (length != vector1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector6"));

		for (i = 0; i < length; i++)
			this.values[i] = vector1.values[i] + vector2.values[i];
	}

	/**
	 * Sets the value of this vector to the vector difference of itself and vector
	 * (this = this - vector).
	 * 
	 * @param vector
	 *          the other vector
	 */
	public final void sub(GVector vector) {
		int i;

		if (length != vector.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector7"));

		for (i = 0; i < length; i++) {
			this.values[i] -= vector.values[i];
		}
	}

	/**
	 * Sets the value of this vector to the vector difference of vectors vector1
	 * and vector2 (this = vector1 - vector2).
	 * 
	 * @param vector1
	 *          the first vector
	 * @param vector2
	 *          the second vector
	 */
	public final void sub(GVector vector1, GVector vector2) {
		int i;

		if (vector1.length != vector2.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector8"));

		if (length != vector1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector9"));

		for (i = 0; i < length; i++)
			this.values[i] = vector1.values[i] - vector2.values[i];
	}

	/**
	 * Multiplies matrix m1 times Vector v1 and places the result into this vector
	 * (this = m1*v1).
	 * 
	 * @param m1
	 *          The matrix in the multiplication
	 * @param v1
	 *          The vector that is multiplied
	 */
	public final void mul(GMatrix m1, GVector v1) {
		if (m1.getNumCol() != v1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector10"));

		if (length != m1.getNumRow())
			throw new MismatchedSizeException(VecMathI18N.getString("GVector11"));

		double v[];
		if (v1 != this) {
			v = v1.values;
		} else {
			v = new double[values.length];
			for (int i = 0; i < values.length; i++) {
				v[i] = values[i];
			}
		}

		for (int j = length - 1; j >= 0; j--) {
			values[j] = 0.0;
			for (int i = v1.length - 1; i >= 0; i--) {
				values[j] += m1.values[j][i] * v[i];
			}
		}
	}

	/**
	 * Multiplies the transpose of vector v1 (ie, v1 becomes a row vector with
	 * respect to the multiplication) times matrix m1 and places the result into
	 * this vector (this = transpose(v1)*m1). The result is technically a row
	 * vector, but the GVector class only knows about column vectors, and so the
	 * result is stored as a column vector.
	 * 
	 * @param m1
	 *          The matrix in the multiplication
	 * @param v1
	 *          The vector that is temporarily transposed
	 */
	public final void mul(GVector v1, GMatrix m1) {
		if (m1.getNumRow() != v1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector12"));

		if (length != m1.getNumCol())
			throw new MismatchedSizeException(VecMathI18N.getString("GVector13"));

		double v[];
		if (v1 != this) {
			v = v1.values;
		} else {
			v = new double[values.length];
			for (int i = 0; i < values.length; i++) {
				v[i] = values[i];
			}
		}

		for (int j = length - 1; j >= 0; j--) {
			values[j] = 0.0;
			for (int i = v1.length - 1; i >= 0; i--) {
				values[j] += m1.values[i][j] * v[i];
			}
		}
	}

	/**
	 * Negates the value of this vector: this = -this.
	 */
	public final void negate() {
		for (int i = length - 1; i >= 0; i--) {
			this.values[i] *= -1.0;
		}
	}

	/**
	 * Sets all the values in this vector to zero.
	 */
	public final void zero() {
		for (int i = 0; i < this.length; i++) {
			this.values[i] = 0.0;
		}
	}

	/**
	 * Changes the size of this vector dynamically. If the size is increased no
	 * data values will be lost. If the size is decreased, only those data values
	 * whose vector positions were eliminated will be lost.
	 * 
	 * @param length
	 *          number of desired elements in this vector
	 */
	public final void setSize(int length) {
		double[] tmp = new double[length];
		int i, max;

		if (this.length < length)
			max = this.length;
		else
			max = length;

		for (i = 0; i < max; i++) {
			tmp[i] = values[i];
		}
		this.length = length;

		values = tmp;

	}

	/**
	 * Sets the value of this vector to the values found in the array parameter.
	 * The array should be at least equal in length to the number of elements in
	 * the vector.
	 * 
	 * @param vector
	 *          the source array
	 */
	public final void set(double[] vector) {
		for (int i = length - 1; i >= 0; i--)
			values[i] = vector[i];
	}

	/**
	 * Sets the value of this vector to the values found in vector vector.
	 * 
	 * @param vector
	 *          the source vector
	 */
	public final void set(GVector vector) {
		int i;

		if (length < vector.length) {
			length = vector.length;
			values = new double[length];
			for (i = 0; i < length; i++)
				values[i] = vector.values[i];
		} else {
			for (i = 0; i < vector.length; i++)
				values[i] = vector.values[i];
			for (i = vector.length; i < length; i++)
				values[i] = 0.0;
		}
	}

	/**
	 * Sets the value of this vector to the values in tuple
	 * 
	 * @param tuple
	 *          the source for the new GVector's new values
	 */
	public final void set(Tuple2f tuple) {
		if (length < 2) {
			length = 2;
			values = new double[2];
		}
		values[0] = (double) tuple.x;
		values[1] = (double) tuple.y;
		for (int i = 2; i < length; i++)
			values[i] = 0.0;

	}

	/**
	 * Sets the value of this vector to the values in tuple
	 * 
	 * @param tuple
	 *          the source for the new GVector's new values
	 */
	public final void set(Tuple3f tuple) {
		if (length < 3) {
			length = 3;
			values = new double[3];
		}
		values[0] = (double) tuple.x;
		values[1] = (double) tuple.y;
		values[2] = (double) tuple.z;
		for (int i = 3; i < length; i++)
			values[i] = 0.0;
	}

	/**
	 * Sets the value of this vector to the values in tuple
	 * 
	 * @param tuple
	 *          the source for the new GVector's new values
	 */
	public final void set(Tuple3d tuple) {
		if (length < 3) {
			length = 3;
			values = new double[3];
		}
		values[0] = tuple.x;
		values[1] = tuple.y;
		values[2] = tuple.z;
		for (int i = 3; i < length; i++)
			values[i] = 0.0;
	}

	/**
	 * Sets the value of this vector to the values in tuple
	 * 
	 * @param tuple
	 *          the source for the new GVector's new values
	 */
	public final void set(Tuple4f tuple) {
		if (length < 4) {
			length = 4;
			values = new double[4];
		}
		values[0] = (double) tuple.x;
		values[1] = (double) tuple.y;
		values[2] = (double) tuple.z;
		values[3] = (double) tuple.w;
		for (int i = 4; i < length; i++)
			values[i] = 0.0;
	}

	/**
	 * Sets the value of this vector to the values in tuple
	 * 
	 * @param tuple
	 *          the source for the new GVector's new values
	 */
	public final void set(Tuple4d tuple) {
		if (length < 4) {
			length = 4;
			values = new double[4];
		}
		values[0] = tuple.x;
		values[1] = tuple.y;
		values[2] = tuple.z;
		values[3] = tuple.w;
		for (int i = 4; i < length; i++)
			values[i] = 0.0;
	}

	/**
	 * Returns the number of elements in this vector.
	 * 
	 * @return number of elements in this vector
	 */
	public final int getSize() {
		return values.length;
	}

	/**
	 * Retrieves the value at the specified index value of this vector.
	 * 
	 * @param index
	 *          the index of the element to retrieve (zero indexed)
	 * @return the value at the indexed element
	 */
	public final double getElement(int index) {
		return values[index];
	}

	/**
	 * Modifies the value at the specified index of this vector.
	 * 
	 * @param index
	 *          the index if the element to modify (zero indexed)
	 * @param value
	 *          the new vector element value
	 */
	public final void setElement(int index, double value) {
		values[index] = value;
	}

	/**
	 * Returns a string that contains the values of this GVector.
	 * 
	 * @return the String representation
	 */
	public String toString() {
		StringBuffer buffer = new StringBuffer(length * 8);

		int i;

		for (i = 0; i < length; i++) {
			buffer.append(values[i]).append(" ");
		}

		return buffer.toString();

	}

	/**
	 * Returns a hash code value based on the data values in this object. Two
	 * different GVector objects with identical data values (i.e., GVector.equals
	 * returns true) will return the same hash number. Two GVector objects with
	 * different data members may return the same hash value, although this is not
	 * likely.
	 * 
	 * @return the integer hash code value
	 */
	public int hashCode() {
		long bits = 1L;

		for (int i = 0; i < length; i++) {
			bits = 31L * bits + VecMathUtil.doubleToLongBits(values[i]);
		}

		return (int) (bits ^ (bits >> 32));
	}

	/**
	 * Returns true if all of the data members of GVector vector1 are equal to the
	 * corresponding data members in this GVector.
	 * 
	 * @param vector1
	 *          The vector with which the comparison is made.
	 * @return true or false
	 */
	public boolean equals(GVector vector1) {
		try {
			if (length != vector1.length)
				return false;

			for (int i = 0; i < length; i++) {
				if (values[i] != vector1.values[i])
					return false;
			}

			return true;
		} catch (NullPointerException e2) {
			return false;
		}

	}

	/**
	 * Returns true if the Object o1 is of type GMatrix and all of the data
	 * members of o1 are equal to the corresponding data members in this GMatrix.
	 * 
	 * @param o1
	 *          The object with which the comparison is made.
	 * @return true or false
	 */
	public boolean equals(Object o1) {
		try {
			GVector v2 = (GVector) o1;

			if (length != v2.length)
				return false;

			for (int i = 0; i < length; i++) {
				if (values[i] != v2.values[i])
					return false;
			}
			return true;
		} catch (ClassCastException e1) {
			return false;
		} catch (NullPointerException e2) {
			return false;
		}

	}

	/**
	 * Returns true if the L-infinite distance between this vector and vector v1
	 * is less than or equal to the epsilon parameter, otherwise returns false.
	 * The L-infinite distance is equal to MAX[abs(x1-x2), abs(y1-y2), . . . ].
	 * 
	 * @param v1
	 *          The vector to be compared to this vector
	 * @param epsilon
	 *          the threshold value
	 */
	public boolean epsilonEquals(GVector v1, double epsilon) {
		double diff;

		if (length != v1.length)
			return false;

		for (int i = 0; i < length; i++) {
			diff = values[i] - v1.values[i];
			if ((diff < 0 ? -diff : diff) > epsilon)
				return false;
		}
		return true;
	}

	/**
	 * Returns the dot product of this vector and vector v1.
	 * 
	 * @param v1
	 *          the other vector
	 * @return the dot product of this and v1
	 */
	public final double dot(GVector v1) {
		if (length != v1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector14"));

		double result = 0.0;
		for (int i = 0; i < length; i++) {
			result += values[i] * v1.values[i];
		}
		return result;
	}

	/**
	 * Solves for x in Ax = b, where x is this vector (nx1), A is mxn, b is mx1,
	 * and A = U*W*transpose(V); U,W,V must be precomputed and can be found by
	 * taking the singular value decomposition (SVD) of A using the method SVD
	 * found in the GMatrix class.
	 * 
	 * @param U
	 *          The U matrix produced by the GMatrix method SVD
	 * @param W
	 *          The W matrix produced by the GMatrix method SVD
	 * @param V
	 *          The V matrix produced by the GMatrix method SVD
	 * @param b
	 *          The b vector in the linear equation Ax = b
	 */
	public final void SVDBackSolve(GMatrix U, GMatrix W, GMatrix V, GVector b) {
		if (!(U.nRow == b.getSize() && U.nRow == U.nCol && U.nRow == W.nRow)) {
			throw new MismatchedSizeException(VecMathI18N.getString("GVector15"));
		}

		if (!(W.nCol == values.length && W.nCol == V.nCol && W.nCol == V.nRow)) {
			throw new MismatchedSizeException(VecMathI18N.getString("GVector23"));
		}

		GMatrix tmp = new GMatrix(U.nRow, W.nCol);
		tmp.mul(U, V);
		tmp.mulTransposeRight(U, W);
		tmp.invert();
		mul(tmp, b);

	}

	/**
	 * LU Decomposition Back Solve; this method takes the LU matrix and the
	 * permutation vector produced by the GMatrix method LUD and solves the
	 * equation (LU)*x = b by placing the solution vector x into this vector. This
	 * vector should be the same length or longer than b.
	 * 
	 * @param LU
	 *          The matrix into which the lower and upper decompostions have been
	 *          placed
	 * @param b
	 *          The b vector in the equation (LU)*x = b
	 * @param permutation
	 *          The row permuations that were necessary to produce the LU matrix
	 *          parameter
	 */
	public final void LUDBackSolve(GMatrix LU, GVector b, GVector permutation) {
		int size = LU.nRow * LU.nCol;

		double[] temp = new double[size];
		double[] result = new double[size];
		int[] row_perm = new int[b.getSize()];
		int i, j;

		if (LU.nRow != b.getSize()) {
			throw new MismatchedSizeException(VecMathI18N.getString("GVector16"));
		}

		if (LU.nRow != permutation.getSize()) {
			throw new MismatchedSizeException(VecMathI18N.getString("GVector24"));
		}

		if (LU.nRow != LU.nCol) {
			throw new MismatchedSizeException(VecMathI18N.getString("GVector25"));
		}

		for (i = 0; i < LU.nRow; i++) {
			for (j = 0; j < LU.nCol; j++) {
				temp[i * LU.nCol + j] = LU.values[i][j];
			}
		}

		for (i = 0; i < size; i++)
			result[i] = 0.0;
		for (i = 0; i < LU.nRow; i++)
			result[i * LU.nCol] = b.values[i];
		for (i = 0; i < LU.nCol; i++)
			row_perm[i] = (int) permutation.values[i];

		GMatrix.luBacksubstitution(LU.nRow, temp, row_perm, result);

		for (i = 0; i < LU.nRow; i++)
			this.values[i] = result[i * LU.nCol];
	}

	/**
	 * Returns the (n-space) angle in radians between this vector and the vector
	 * parameter; the return value is constrained to the range [0,PI].
	 * 
	 * @param v1
	 *          The other vector
	 * @return The angle in radians in the range [0,PI]
	 */
	public final double angle(GVector v1) {
		return (Math.acos(this.dot(v1) / (this.norm() * v1.norm())));
	}

	/**
	 * @deprecated Use interpolate(GVector, GVector, double) instead
	 */
	public final void interpolate(GVector v1, GVector v2, float alpha) {
		interpolate(v1, v2, (double) alpha);
	}

	/**
	 * @deprecated Use interpolate(GVector, double) instead
	 */
	public final void interpolate(GVector v1, float alpha) {
		interpolate(v1, (double) alpha);
	}

	/**
	 * Linearly interpolates between vectors v1 and v2 and places the result into
	 * this tuple: this = (1-alpha)*v1 + alpha*v2.
	 * 
	 * @param v1
	 *          the first vector
	 * @param v2
	 *          the second vector
	 * @param alpha
	 *          the alpha interpolation parameter
	 */
	public final void interpolate(GVector v1, GVector v2, double alpha) {
		if (v2.length != v1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector20"));

		if (length != v1.length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector21"));

		for (int i = 0; i < length; i++) {
			values[i] = (1 - alpha) * v1.values[i] + alpha * v2.values[i];
		}
	}

	/**
	 * Linearly interpolates between this vector and vector v1 and places the
	 * result into this tuple: this = (1-alpha)*this + alpha*v1.
	 * 
	 * @param v1
	 *          the first vector
	 * @param alpha
	 *          the alpha interpolation parameter
	 */
	public final void interpolate(GVector v1, double alpha) {
		if (v1.length != length)
			throw new MismatchedSizeException(VecMathI18N.getString("GVector22"));

		for (int i = 0; i < length; i++) {
			values[i] = (1 - alpha) * values[i] + alpha * v1.values[i];
		}
	}
}
